﻿using DllInject.Properties;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace DllInject
{
    public partial class Form1 : Form
    {

        public static ulong Kernel32Handle;
        private int Current_Pid;
        private Hashtable Process_IDS = new Hashtable();
        private SortedSet<Native.Module> Current_Loaded_DLLs = new SortedSet<Native.Module>(new SoetedProcessMoudleB());
        private SortedSet<string> Process_Names = new SortedSet<string>(new Sorted());

        public Form1()
        {
            InitializeComponent();
        }


        private void textBox2_KeyPress(object sender, KeyPressEventArgs e)
        {
            e.Handled = true;
            if (Char.IsDigit(e.KeyChar) && e.KeyChar!='.')
                e.Handled = false;
        }


        private void Form1_Load(object sender, EventArgs e)
        {
            LoadProcess();
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            int id = (int)this.Process_IDS[this.comboBox1.SelectedItem.ToString()];
            this.Current_Pid = id;
            this.textBox2.Text = ""+id;
            LoadLoadedDLL();
        }

        private void LoadProcess() {
            Process[] process = Process.GetProcesses();
            this.Process_IDS.Clear();
            this.Process_Names.Clear();
            foreach (var p in process) {
                try
                {
                    string name = p.MainModule.ModuleName + $"({p.Id})"; 
                    this.Process_Names.Add(name);
                    this.Process_IDS.Add(name, p.Id);
                }
                catch {
                }
           
            }
            this.comboBox1.Items.Clear();
            this.comboBox1.Items.AddRange(this.Process_Names.ToArray());
        }

        private void LoadLoadedDLL() {

            try
            {
                Process process = Process.GetProcessById(this.Current_Pid);
                ulong[] hMods = new ulong[1024];
                uint need = 0;
                IntPtr hProcess = Native.OpenProcess(Native.PROCESS_ALL_ACCESS, false, process.Id);

                if (!Native.EnumProcessModulesEx(hProcess, hMods, hMods.Length, out need, (int)Native.ModuleFilter.LIST_MODULES_ALL))
                {
                    throw new Exception("EnumProcessModulesEx fail");
                }
                this.Current_Loaded_DLLs.Clear();
                this.listView2.Items.Clear();
                this.listView2.BeginUpdate();
                for (int i = 0; i < need / IntPtr.Size; i++)
                {
                    byte[] b = new byte[1024];
                    if (Native.K32GetModuleFileNameExW(hProcess, hMods[i], b, b.Length) == 0)
                    {
                        throw new Exception("GetModuleFileName fail");
                    }
                    string name = Encoding.Unicode.GetString(b).Replace("\x00", "");
                    if (name.Contains(@"C:\WINDOWS\System32\KERNEL32.DLL"))
                    {
                        Kernel32Handle = hMods[i];
                    }

                    Console.WriteLine(name);

                    Native.ModuleInformation moduleInformation = new Native.ModuleInformation();
                    Native.K32GetModuleInformation(hProcess, hMods[i], out moduleInformation, (uint)(IntPtr.Size * (hMods.Length)));

                    this.Current_Loaded_DLLs.Add(new Native.Module(name,moduleInformation.lpBaseOfDll,moduleInformation.SizeOfImage));

                    ListViewItem listViewItem = new ListViewItem();
                    listViewItem.Text = name;
                    listViewItem.SubItems.Add("0x" + Convert.ToString((long)moduleInformation.lpBaseOfDll, 16).ToUpper());
                    this.listView2.Items.Add(listViewItem);
                }
                this.listView2.EndUpdate();

            }
            catch (Exception ee){
               MessageBox.Show(ee.Message);
            }
        }

        //public SortedSet<Native.Module> CollectModules(IntPtr process)
        //{
        //    SortedSet<Native.Module> collectedModules = new SortedSet<Native.Module>(new SoetedProcessMoudleB());

        //    ulong[] modulePointers = new ulong[0];
        //    uint bytesNeeded = 0;

        //    // Determine number of modules
        //    if (!Native.EnumProcessModulesEx(process, modulePointers, 0, out bytesNeeded, (int)Native.ModuleFilter.LIST_MODULES_ALL))
        //    {
        //        return collectedModules;
        //    }

        //    uint totalNumberofModules = (uint)(bytesNeeded / IntPtr.Size);
        //    modulePointers = new ulong[totalNumberofModules];

        //        for (int index = 0; index < totalNumberofModules; index++)
        //        {
        //            byte[] moduleFilePath = new byte[1024];
        //            Native.K32GetModuleFileNameExW(process, modulePointers[index], moduleFilePath, (moduleFilePath.Length));

        //            string moduleName = Path.GetFileName(moduleFilePath.ToString());
        //            Native.ModuleInformation moduleInformation = new Native.ModuleInformation();
        //            Native.K32GetModuleInformation(process, modulePointers[index], out moduleInformation, (uint)(IntPtr.Size * (modulePointers.Length)));

        //            // Convert to a normalized module and add it to our list
        //            Native.Module module = new Native.Module(moduleName, moduleInformation.lpBaseOfDll, moduleInformation.SizeOfImage);
        //            collectedModules.Add(module);
        //        }

        //    return collectedModules;
        //}

    private void button4_Click(object sender, EventArgs e)
        {
            LoadLoadedDLL();
        }

        private void listView1_DragEnter(object sender, DragEventArgs e)
        {
            Console.WriteLine(e.Data.GetDataPresent(DataFormats.FileDrop));
        }

        private void button3_Click(object sender, EventArgs e)
        {
            OpenFileDialog save = new OpenFileDialog();
            save.Multiselect = true;
            save.Filter = "应用程序扩展|*.dll";
            if (save.ShowDialog() == DialogResult.OK) {
                foreach (string filename in save.FileNames) {
                    ListViewItem listViewItem = new ListViewItem();
                    listViewItem.Text = filename;
                    //listViewItem.SubItems.Add();
                    this.listView1.Items.Add(listViewItem);
                }
            }
        }

        private void button6_Click(object sender, EventArgs e)
        {
            this.listView1.Items.Clear();
        }

        private void button5_Click(object sender, EventArgs e)
        {

            for (int i = listView1.SelectedItems.Count - 1; i >= 0; i--)
            {
                ListViewItem item = listView1.SelectedItems[i];
                this.listView1.Items.Remove(item);
            }

        }



        private void button1_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem item in this.listView1.Items)
            {
                Console.WriteLine($"Inject Dll: {item.Text}");
                string filename = item.Text;
                Injector.Inject(this.Current_Pid, item.Text,Kernel32Handle);
            }
            LoadLoadedDLL();
        }

        private void button2_Click(object sender, EventArgs e)
        {

        }

        private void textBox2_TextChanged(object sender, EventArgs e)
        {
            this.Current_Pid = Convert.ToInt32(this.textBox2.Text.Trim());
        }
    }

    class Sorted : IComparer<string>
    {

        public int Compare(string x, string y)
        {
            return String.Compare(x, y);
        }
    }



    class SoetedProcessMoudleB : IComparer<Native.Module>
    {

        public int Compare(Native.Module x, Native.Module y)
        {
            return String.Compare(x.ModuleName, y.ModuleName);
        }
    }

}
